﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.ColorSpaces;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This is an own creation, 
    /// this just converts given pixels into a
    /// GetColorConstancy2 Formula and then puts the results
    /// back into pixel colors
    /// </summary>
    public class ColorRGBMap : BaseImageFilter
    {
        // color maps
        private byte[] redMap;
        private byte[] greenMap;
        private byte[] blueMap;
        private byte[] grayMap;

        /// <summary>
        /// default constructor
        /// </summary>
        public ColorRGBMap()
        {
            redMap = new byte[256];
            greenMap = new byte[256];
            blueMap = new byte[256];
            grayMap = new byte[256];

            //SetRGBNonChangingDefaultMap();
            SetDefaultMap();
        }

        public void SetRGBNonChangingDefaultMap()
        {
            // fill the maps
            for (int i = 0; i < 256; i++)
            {
                redMap[i] = greenMap[i] = blueMap[i] = grayMap[i] = (byte)i;
            }
        }

        public void SetDefaultMap()
        {
            // create map
            byte[] map = new byte[256];
            for (int i = 0; i < 256; i++)
            {
                map[i] = (byte)Math.Min(255, Math.Pow(2, (double)i / 32));
            }
            greenMap = map;
            redMap = map;
            blueMap = map;
        }

        /// <summary>
        /// specify angle directly
        /// </summary>
        /// <param name="_dAngle"></param>
        public ColorRGBMap(double _dAngle)
        {
        }

        /// <summary>
        /// used to copy this instance
        /// </summary>
        /// <param name="_colorRGBMap"></param>
        internal ColorRGBMap(ColorRGBMap _colorRGBMap)
        {
            redMap = _colorRGBMap.redMap;
            blueMap = _colorRGBMap.blueMap;
            greenMap = _colorRGBMap.greenMap;
        }

        /// <summary>
        /// Remapping array for red color plane.
        /// </summary>
        /// 
        /// <remarks><para>The remapping array should contain 256 remapping values. The remapping occurs
        /// by changing pixel's red value <b>r</b> to <see cref="RedMap"/>[r].</para></remarks>
        /// 
        /// <exception cref="ArgumentException">A map should be array with 256 value.</exception>
        /// 
        public byte[] RedMap
        {
            get { return redMap; }
            set
            {
                // check the map
                if ((value == null) || (value.Length != 256))
                    throw new ArgumentException("A map should be array with 256 value.");

                redMap = value;
            }
        }

        /// <summary>
        /// Remapping array for green color plane.
        /// </summary>
        /// 
        /// <remarks><para>The remapping array should contain 256 remapping values. The remapping occurs
        /// by changing pixel's green value <b>g</b> to <see cref="GreenMap"/>[g].</para></remarks>
        /// 
        /// <exception cref="ArgumentException">A map should be array with 256 value.</exception>
        /// 
        public byte[] GreenMap
        {
            get { return greenMap; }
            set
            {
                // check the map
                if ((value == null) || (value.Length != 256))
                    throw new ArgumentException("A map should be array with 256 value.");

                greenMap = value;
            }
        }

        /// <summary>
        /// Remapping array for blue color plane.
        /// </summary>
        /// 
        /// <remarks><para>The remapping array should contain 256 remapping values. The remapping occurs
        /// by changing pixel's blue value <b>b</b> to <see cref="BlueMap"/>[b].</para></remarks>
        /// 
        /// <exception cref="ArgumentException">A map should be array with 256 value.</exception>
        /// 
        public byte[] BlueMap
        {
            get { return blueMap; }
            set
            {
                // check the map
                if ((value == null) || (value.Length != 256))
                    throw new ArgumentException("A map should be array with 256 value.");

                blueMap = value;
            }
        }

        /// <summary>
        /// executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;

            // RGB image
            Color color = Definitions.White;
            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    // red
                    byte r = redMap[_bitmap[x, y].R];
                    // green
                    byte g = greenMap[_bitmap[x, y].G];
                    // blue
                    byte b = blueMap[_bitmap[x, y].B];
                    _bitmap.SetPixelDirect(x, y, r, g, b);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ColorRGBMap(this);
        }
    }
}
